package com.pz.gulimall.order.rabbitmq;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.pz.gulimall.common.constant.OrderStatusEnum;
import com.pz.gulimall.common.exception.BizCodeEnum;
import com.pz.gulimall.common.exception.RRException;
import com.pz.gulimall.common.to.mq.OrderPayFinishedMsg;
import com.pz.gulimall.common.to.mq.OrderReleaseTo;
import com.pz.gulimall.order.entity.OrderEntity;
import com.pz.gulimall.order.entity.PaymentInfoEntity;
import com.pz.gulimall.order.service.OrderService;
import com.pz.gulimall.order.service.PaymentInfoService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.concurrent.ListenableFutureCallback;

import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.UUID;

import static com.pz.gulimall.order.config.MQConfig.*;

@Component
@Slf4j
public class OrderListener {
    @Resource
    private OrderService orderService;
    @Resource
    private PaymentInfoService paymentInfoService;
    @Resource
    private RabbitTemplate rabbitTemplate;

    /**
     * 处理超时未支付订单
     */
    @RabbitListener(queues = orderReleaseQueName)
    public void handleOrderRelease(Message msg, Channel channel, OrderReleaseTo orderReleaseTo){
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        //检验订单状态，若是未付款主动关闭订单
        Integer status = orderService.checkOrderStatus(orderReleaseTo.getOrderId());
        if (status.intValue() == OrderStatusEnum.CREATE_NEW.getCode().intValue()) {
            orderService.updateOrderStatus(orderReleaseTo.getOrderId(), OrderStatusEnum.CANCLED.getCode());

            // TODO 发送消息通知其他服务释放订单相关的资源
            CorrelationData cd = new CorrelationData(UUID.randomUUID().toString());
            rabbitTemplate.convertAndSend(orderEventExchangeName, "order.release.other", orderReleaseTo, cd);
            cd.getFuture().addCallback(new ListenableFutureCallback<CorrelationData.Confirm>() {
                @Override
                public void onFailure(@NotNull Throwable ex) {
                    log.info("消息发送失败-{}",ex.getMessage());
                    try {
                        channel.basicNack(deliveryTag, false, true);
                    } catch (IOException e) {
                        throw new RRException(BizCodeEnum.RABBITMQ_ACK_EXCEPTION, e.getMessage());
                    }
                }

                @Override
                public void onSuccess(CorrelationData.Confirm result) {
                    try {
                        if (result.isAck()) {
                            channel.basicAck(deliveryTag, false);
                        } else {
                            channel.basicNack(deliveryTag, false, true);
                        }
                    } catch (IOException e) {
                        throw new RRException(BizCodeEnum.RABBITMQ_ACK_EXCEPTION, e.getMessage());
                    }
                }
            });
        }

    }

    /**
     * 处理支付成功订单后的订单数据
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(name = "order.finnish.order.que"),
            exchange = @Exchange(name = "orderEvent.exchange", type = ExchangeTypes.TOPIC),
            key = {"order.finish.#"}
    ))
    @RabbitHandler
    @Transactional
    public void handleOrderFinnishOrder(OrderPayFinishedMsg finishedMsg, Message msg, Channel channel) {
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        log.info("处理订单-{}", finishedMsg);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 更新订单状态和付款时间
        try {
            orderService.update(new UpdateWrapper<OrderEntity>().eq("order_sn", finishedMsg.getOut_trade_no())
                    .set("status", OrderStatusEnum.PAYED.getCode())
                    .set("payment_time", sdf.parse(finishedMsg.getGmt_payment()))
            );
            OrderEntity order = orderService.getOne(new QueryWrapper<OrderEntity>().eq("order_sn", finishedMsg.getOut_trade_no()));

            //保存交易流水
            PaymentInfoEntity paymentInfoEntity = new PaymentInfoEntity();
            paymentInfoEntity.setOrderSn(finishedMsg.getOut_trade_no());
            paymentInfoEntity.setOrderId(order.getId());
            paymentInfoEntity.setAlipayTradeNo(finishedMsg.getTrade_no());
            paymentInfoEntity.setTotalAmount(new BigDecimal(finishedMsg.getTotal_amount()));
            paymentInfoEntity.setSubject(finishedMsg.getBody());
            paymentInfoEntity.setPaymentStatus(finishedMsg.getTrade_status());
            paymentInfoEntity.setCreateTime(sdf.parse(finishedMsg.getGmt_create()));
            paymentInfoEntity.setConfirmTime(sdf.parse(finishedMsg.getGmt_payment()));
            paymentInfoEntity.setCallbackTime(sdf.parse(finishedMsg.getNotify_time()));

            paymentInfoService.save(paymentInfoEntity);
        } catch (ParseException e) {
            log.error("时间转换异常-{}",e.getMessage());
        }
        try {
            channel.basicAck(deliveryTag, false);
        } catch (IOException e) {
            throw new RRException(BizCodeEnum.RABBITMQ_ACK_EXCEPTION, e.getMessage());
        }
    }
}
